package com.dahua.messagesyncbj.service.Impl;

import com.alibaba.fastjson2.JSON;
import com.dahua.messagesyncbj.business.Constants;
import com.dahua.messagesyncbj.config.redis.RedisUtil;
import com.dahua.messagesyncbj.criteria.FaultQueryCriteria;
import com.dahua.messagesyncbj.criteria.SensorQueryCriteria;
import com.dahua.messagesyncbj.criteria.StatusQueryCriteria;
import com.dahua.messagesyncbj.entity.*;
import com.dahua.messagesyncbj.mapper.EquipmentMapper;
import com.dahua.messagesyncbj.mapper.FaultMapper;
import com.dahua.messagesyncbj.mapper.SensorMapper;
import com.dahua.messagesyncbj.pojo.EquipmentInfo;
import com.dahua.messagesyncbj.criteria.EquipmentInfoQueryCriteria;
import com.dahua.messagesyncbj.service.EquipmentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;

import static com.dahua.messagesyncbj.business.Constants.*;

@Slf4j
@Service
public class EquipmentServiceImpl implements EquipmentService {
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private SensorMapper sensorMapper;
    @Resource
    private EquipmentMapper equipmentMapper;
    @Resource
    private FaultMapper faultMapper;

    @Override
    public void resetEquipmentInfo() {
        redisUtil.deleteKey(EQUIPMENT_HASH);
        List<String> types = equipmentMapper.listTypes(37, Constants.ORIGINAL_TYPES, false);
        List<Equipment> equipments = equipmentMapper.listEquipments(types, true);
        equipments.forEach(
                (item) -> {
                    redisUtil.setHash(EQUIPMENT_HASH, item.getName(), new EquipmentInfo(
                            item.getId(), item.getName(), item.getLineId(), item.getStationId(), item.getBk2(), item.getBk5(), item.getBk82()
                    ));
                }
        );
    }

    //状态测点信息
    @Override
    public void resetSensorInfo() {
        //redisUtil.deleteKey(SENSOR_HASH);
        List<Sensor> sensors = sensorMapper.listSensors(SensorQueryCriteria.builder().isStatus(1).build());
        Map<String, List<Sensor>> map = new HashMap<>();
        Map<String, Map<String, List<Sensor>>> p_map = new HashMap<>();
        for (Sensor sensor : sensors) {
            if (sensor.getParentType() == null) {
                if (map.isEmpty() || !map.containsKey(sensor.getEquipmentType())) {
                    map.put(sensor.getEquipmentType(), Arrays.asList(sensor));
                } else {
                    List<Sensor> list = new ArrayList<>();
                    list = JSON.parseObject(JSON.toJSONString(map.get(sensor.getEquipmentType())), List.class);
                    list.add(sensor);
                    map.put(sensor.getEquipmentType(), list);
                }
            } else {
                if (p_map.isEmpty() || !p_map.containsKey(sensor.getParentType())) {
                    Map<String, List<Sensor>> temp = new HashMap<>();
                    temp.put(sensor.getBk1(), Arrays.asList(sensor));
                    p_map.put(sensor.getParentType(), temp);
                } else {
                    Map<String, List<Sensor>> item = p_map.get(sensor.getParentType());
                    if (item.isEmpty() || !item.containsKey(sensor.getBk1())) {
                        item.put(sensor.getBk1(), Arrays.asList(sensor));
                    } else {
                        List<Sensor> list = new ArrayList<>();
                        list = JSON.parseObject(JSON.toJSONString(item.get(sensor.getBk1())), List.class);
                        list.add(sensor);
                        item.put(sensor.getBk1(), list);
                    }
                }
            }
        }

        //set redis
        map.forEach(
                (key, item) -> {
                    Map<String, List<Sensor>> sensor = new HashMap<>();
                    sensor.put("ALL", item);
                    redisUtil.setHash(SENSOR_HASH, key, sensor);
                }
        );

        p_map.forEach(
                (m_key, m_item) -> {
                    redisUtil.setHash(SENSOR_HASH, m_key, m_item);
                }
        );
    }

    @Override
    public void resetSensorInfoRemake() {
        List<Sensor> sensors = sensorMapper.listSensors(SensorQueryCriteria.builder().isStatus(1).build());

        sensors.forEach(
                (item) -> {
                    redisUtil.setHash(SENSOR_HASH, item.getBk1(), item);
                }
        );
    }

    @Override
    public void resetLatestStatus() {
        redisUtil.deleteKey(LATEST_STATUS_HASH);
        List<Status> statuses = equipmentMapper.listLatestStatus(new StatusQueryCriteria());
        for (Status item : statuses) {
            redisUtil.setHash(LATEST_STATUS_HASH, item.getManufactureId(), item);
        }
    }

    @Override
    public void checkInsertLatestStatus() {
        List<Equipment> equipments = equipmentMapper.listEquipments(ORIGINAL_TYPES, false);
        for (Equipment equipment : equipments) {
            List<Status> statuses = this.listLatestStatus(new StatusQueryCriteria(equipment.getName()));
            if (statuses.isEmpty()) {
                Status status = new Status();
                status.setLineId(equipment.getLineId());
                status.setStationId(equipment.getStationId());
                status.setEquipmentId(equipment.getId());
                status.setManufactureId(equipment.getName());
                status.setEquipmentType(equipment.getBk2());
                status.setLogTime(Timestamp.valueOf(LocalDateTime.now().minusDays(1L)));
                status.setIsMachine(0);

                this.setStatus(equipment, status);
                this.insertLatestStatus(status);
            }
        }
    }

    public void setStatus(Equipment equipment, Status status) {
        FaultQueryCriteria faultQueryCriteria = new FaultQueryCriteria();
        faultQueryCriteria.setManufactureId(equipment.getName());
        faultQueryCriteria.setIsFixed(0);
        List<Fault> faults = faultMapper.listFaults(faultQueryCriteria);

        int eventLevel_A = 0;
        int eventLevel_B = 0;
        for (int i = 0; i < faults.size(); i++) {
            if (faults.get(i).getSensorType().charAt(0) > 65) {
                if (faults.get(i).getEventLevel() > eventLevel_B) {
                    eventLevel_B = faults.get(i).getEventLevel();
                }
            } else {
                if (faults.get(i).getEventLevel() > eventLevel_A) {
                    eventLevel_A = faults.get(i).getEventLevel();
                }
            }

        }
        if (eventLevel_B != 0) {
            status.setSensorType("B");
            status.setStatus(eventLevel_B);
        } else if (eventLevel_A != 0) {
            status.setSensorType("A");
            status.setStatus(eventLevel_A);
        }
    }

    @Override
    public EquipmentInfo enquire(String name) {
        EquipmentInfo info = null;
        //读redis
        try {
            Object hash = redisUtil.getHash(Constants.EQUIPMENT_HASH, name);
            if (hash != null && hash.equals(NULL_STRING)){
                return null;
            }
            info = JSON.parseObject(JSON.toJSONString(hash), EquipmentInfo.class);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        //写redis
        if (info == null) {
            EquipmentInfoQueryCriteria criteria = new EquipmentInfoQueryCriteria();
            criteria.setName(name);
            info = equipmentMapper.enquire(criteria);
            if (info != null) {
                redisUtil.setHash(EQUIPMENT_HASH, name, info);
            }else{
                //避免多次查表，设置空值，当设备加入才在SyncScheduleRunner中更新
                log.error("【查询不到当前设备信息】：{}",name);
                redisUtil.setHash(EQUIPMENT_HASH, name, NULL_STRING);
            }
        }
        return info;
    }

    @Override
    public List<Equipment> listEquipments(List<String> bk2List, boolean is_in) {
        return equipmentMapper.listEquipments(bk2List, is_in);
    }

    @Override
    public List<String> listTypes(int dictId, List<String> labelList, boolean is_in) {
        return equipmentMapper.listTypes(dictId, labelList, is_in);
    }

    @Override
    public List<Status> listLatestStatus(StatusQueryCriteria statusQuery) {
        Object hash = redisUtil.getHash(LATEST_STATUS_HASH, statusQuery.getManufactureId());
        if (hash == null) {
            List<Status> statuses = equipmentMapper.listLatestStatus(statusQuery);
            if (statuses != null && statuses.size() == 1) {
                redisUtil.setHash(LATEST_STATUS_HASH, statuses.get(0).getManufactureId(), statuses.get(0));
            }
            if (statuses == null || statuses.isEmpty()){
                log.error("【查询不到当前设备状态信息】：{}", statusQuery);
            }
            return statuses;
        }

        Status r_status = null;
        try{
             r_status = JSON.parseObject(JSON.toJSONString(hash), Status.class);
        }catch (Exception e){
            log.error("【缓存中的设备信息错误】：{}", hash);
            redisUtil.deleteHash(LATEST_STATUS_HASH, statusQuery.getManufactureId());
            return listLatestStatus(statusQuery);
        }
        return Collections.singletonList(r_status);
    }

    @Override
    public boolean updateLatestStatus(Status status) {
        if (status.getEquipmentId() != 0 || status.getManufactureId() != null) {
            redisUtil.setHash(LATEST_STATUS_HASH, status.getManufactureId(), status);
            return equipmentMapper.updateLatestStatus(status);
        }
        return false;
    }

    @Override
    public boolean updateLatestStatusBatch(List<Status> statuses) {
        Map<Integer,Status> map = new HashMap<>();

        for (Status status : statuses){
            if (map.isEmpty()){
                map.put(status.getEquipmentId(),status);
                continue;
            }

            if (map.containsKey(status.getEquipmentId())){
                Status item = map.get(status.getEquipmentId());
                if (item.getLogTime().before(status.getLogTime())){
                    map.put(status.getEquipmentId(),status);
                }
            }else{
                map.put(status.getEquipmentId(),status);
            }
        }

        List<Status> insert = new ArrayList<>();
        for (Map.Entry<Integer,Status> entry : map.entrySet()){
            insert.add(entry.getValue());
        }

        equipmentMapper.updateLatestStatusBatch(insert);

        return false;
    }

    @Override
    public boolean insertLatestStatus(Status status) {
        if (status.getLineId() == 0 || status.getStationId() == 0 || status.getEquipmentId() == 0 ||
                status.getManufactureId() == null || status.getEquipmentType() == null || status.getLogTime() == null) {
            return false;
        }

        //如果是机械硬件，需要将is_machine置为1
        /*String macType = status.getManufactureId().replaceAll("\\s*", "")
                .replaceAll("[^(a-zA-Z)]", "");
        if (MACHINE_TYPES.contains(macType)) {
            status.setIsMachine(1);
        }*/

        redisUtil.setHash(LATEST_STATUS_HASH, status.getManufactureId(), status);
        return equipmentMapper.insertLatestStatus(status);
    }


    @Override
    @Transactional
    public boolean deleteLatestStatus(List<Status> statues) {
        for (Status status : statues) {
            if (status.getEquipmentId() == 0 && status.getManufactureId() == null) {
                return false;
            }
            equipmentMapper.deleteLatestStatus(status);
        }
        return true;
    }

    @Override
    public List<Sensor> listSensors(SensorQueryCriteria sensorQueryCriteria) {
        //如果是查询特定类型测点集的状态测点，直接在缓存中获取
        if (sensorQueryCriteria.getBk1() != null && sensorQueryCriteria.getIsStatus() != null && sensorQueryCriteria.getIsStatus() == 1){
            Object hash = redisUtil.getHash(SENSOR_HASH, sensorQueryCriteria.getBk1());
            if (hash != null){
                if (hash.equals(NULL_STRING)){
                    return Collections.emptyList();
                }

                return Collections.singletonList(JSON.parseObject(JSON.toJSONString(hash), Sensor.class));
            }
            else{
                List<Sensor> sensors = sensorMapper.listSensors(sensorQueryCriteria);
                if (sensors == null || sensors.isEmpty()){
                    log.error("【查询不到状态测点】：{}", sensorQueryCriteria);
                    redisUtil.setHash(SENSOR_HASH, sensorQueryCriteria.getBk1(), NULL_STRING);
                    return Collections.emptyList();

                }else if (sensors.size() == 1){
                    redisUtil.setHash(SENSOR_HASH, sensorQueryCriteria.getBk1(), sensors.get(0));
                    return sensors;

                }else {
                    log.error("【查询到多个状态测点】：{}", sensorQueryCriteria);
                    return Collections.emptyList();

                }
            }
        }
        return sensorMapper.listSensors(sensorQueryCriteria);
    }
}
